/*
 * test_com.cpp
 *
 *  Created on: 2016年12月18日
 *      Author: work
 */

#include <iostream>
#include <boost/program_options.hpp>
#include <dm/os/com/address.hpp>

#include <boost/smart_ptr.hpp>
#include <dm/os/ascom/device.hpp>
#include <dm/os/ascom/serialdevice.hpp>
#include <dm/os/ascom/stdindevice.hpp>
#include <dm/os/ascom/tcplistner.hpp>
#include <dm/os/ascom/tcpclientdevice.hpp>
#include <dm/os/ascom/tcpconnecteddevice.hpp>
#include <dm/os/ascom/timer.hpp>
#include <dm/os/ascom/udpclientdevice.hpp>

using namespace std;
using namespace boost::program_options;

boost::shared_ptr<dm::os::ascom::CTcpClientDevice> tcpClientDevice;
boost::shared_ptr<dm::os::ascom::CTcpListner> tcpAcceptorDevice;
boost::shared_ptr<dm::os::ascom::CUdpClientDevice> udpDevice;
boost::shared_ptr<dm::os::ascom::CSerialDevice> serialDevice;
boost::shared_ptr<dm::os::ascom::CTimer> timer;
boost::shared_ptr<dm::os::ascom::CStdInDevice> stdInDevice;

dm::os::ascom::CDevice* asComDevice = NULL;
dm::os::com::CDevice* comDevice = NULL;

void connecteOk(){
	cout <<"连接成功"<<endl;
}

void connectKo(){
	cout <<"连接失败"<<endl;
}

void rxed( const dm::uint8* buf,const size_t& len ){
	printf("rx(%d):",len);
	for( unsigned int i=0;i<len;++i )
		printf("%02X ",buf[i]);
	printf("\n");
}

void rxKo(){
	cout <<"rx failed"<<endl;
}

void txOk(){
	cout <<"tx success"<<endl;
}

void txKo(){
	cout <<"tx failed"<<endl;
}

dm::uint8 msg[10] = { "hello" };

void timeout(){
	cout <<"tx >>"<<endl;
	if( tcpClientDevice )
		tcpClientDevice->asynSend(msg,10);
	if( udpDevice )
		udpDevice->asynSend(msg,10);
	if( serialDevice )
		serialDevice->asynSend(msg,10);
}

void accept_new( dm::os::com::CTcpListener::device_t& connect ){
	static dm::os::com::CTcpListener::device_t lc;
	lc = connect;
}

void stdinhandle( const dm::uint8* buf,const size_t& size ){
	timeout();
}

int main( int argc,char* argv[] ){
	options_description desc("DM通信模块工具");
	desc.add_options()
			("help,h","显示本帮助信息")
			("version,v","显示版本及编译信息")
			("addr",value<string>(),"设备地址\n SRP:/dev/ttyS1:115200:8:0:0:0\n USR:localhost:2013\n UCL:server:2013\n UBL:localhost:2013:server:2013\n TSR:localhost:2013\n TCL:server:2013")
			("auto,a",value<int>(),"自动发送时间间隔")
			;

	variables_map vm;
	try{
		store(parse_command_line(argc,argv,desc),vm);
		notify(vm);
	}catch( std::exception& ex ){
		cout << ex.what()<<endl;
		return 1;
	}

	if( vm.count("version") ){
		cout <<"V1.0 构建于 "<<__DATE__<<endl;
		return 1;
	}

	if( vm.count("help") ){
		cout <<desc<<endl;
		return 1;
	}

	boost::asio::io_service ios;

	try{
		if( !vm.count("addr") ){
			cout <<"必须指定地址"<<endl;
			return -1;
		}

		dm::os::com::CComAddr addr;
		addr.fromString(vm["addr"].as<string>().c_str());

		boost::shared_ptr<dm::os::com::CTcpServerAddr> addr_tcpServer;

		switch( addr.type() ){
		case dm::os::com::CComAddr::TcpServer:
			tcpAcceptorDevice.reset( new dm::os::ascom::CTcpAcceptor(ios) );
			addr_tcpServer = addr.asTcpServer();
			tcpAcceptorDevice->listen(addr_tcpServer->getHost(),addr_tcpServer->getPort(),true);

			tcpAcceptorDevice->sig_newCon.connect(accept_new);

			break;

		case dm::os::com::CComAddr::TcpClient:
			tcpClientDevice.reset( new dm::os::ascom::CTcpClientDevice(ios) );
			asComDevice = tcpClientDevice.get();
			comDevice = tcpClientDevice.get();

			break;

		case dm::os::com::CComAddr::UdpServer:
			addr_udpServer = addr.asUdpServer();

			udpDevice.reset( new dm::os::ascom::CUdpDevice(ios) );
			udpDevice->setLocalEnd( addr_udpServer->getHost(),addr_udpServer->getPort() );
			udpDevice->sig_rx.connect(rxed);

			udpDevice->rx(true);

			break;
		case dm::os::com::CComAddr::UdpClient:
			addr_udpClient = addr.asUdpClinet();

			udpDevice.reset( new dm::os::ascom::CUdpDevice(ios));
			udpDevice->setRemoteEnd( addr_udpClient->getServer(),addr_udpClient->getPort());
			udpDevice->sig_rx.connect(rxed);
			udpDevice->sig_rxKo.connect(rxKo);
			udpDevice->sig_txOk.connect(txOk);
			udpDevice->sig_txKo.connect(txKo);

			udpDevice->rx(true);

			break;

		case dm::os::com::CComAddr::SerialPort:
			serialDevice.reset( new dm::os::ascom::CSerialDevice(ios) );

			asComDevice = serialDevice.get();
			comDevice = serialDevice.get();

			break;
		default:
			cout <<"请检查地址是否正确"<<vm["addr"].as<string>()<<endl;
			return -1;
		}

		comDevice->setAddress(addr);
		comDevice->setRxAuto();
		comDevice->open();
		comDevice->rxAuto();

		asComDevice->setRx(rxed);
		asComDevice->setRxKo(rxKo);
		asComDevice->setTxOk( txOk );
		asComDevice->setTxKo( txKo );

		if( vm.count("auto") ){
			timer.reset( new dm::os::ascom::CTimer(ios));
			timer->sig_timeout.connect(timeout);
			timer->startAuto( boost::posix_time::microseconds(vm["auto"].as<int>()) );
		}else{
			stdInDevice.reset( new dm::os::ascom::CStdInDevice(ios) );
			stdInDevice->setRx(stdinhandle);
			stdInDevice->rxAuto();
		}

		ios.run();
	}catch( std::exception& e ){
		cout <<"error:"<<e.what()<<endl;
	}

	return 0;
}
